#include <stdio.h>
#include <stdlib.h>

double expon(double *, float);

#define NJOB 3		//The number of customers per run
#define EXPARRI 5		//The expected customer interarrival time
#define EXPSERVICE 20		//The expected service time
#define INFINITE 1000000	//Indicate a very large value
#define IDLE 0
#define BUSY 1
#define N 3					//Number of queues in a tandem queue			

double seed = 7654321;
double arrive[NJOB];


int i[N];				//current customer being served
int j[N];				//next customer to arrive
double clock[N];		//clock for each server
double servstatus[N];	//status of each server
double nextarrive[N];	//next arrival event for each server
double nextdepart[N];	//next departure event for each server
int queuelen[N];		//queue length of each server
int finish = 0;			//record #jobs that have finished all services

int isarrive;			//earlest event is arrive or not
int earliestqueue;		//in which queue the earliest event occurs
double earliesttime;		//the time of the earliest event

//Time of arrival to the first queue of each job
void init(void)
{
	int k;
	arrive[0] = expon(&seed,EXPARRI);
	for(k=1; k<NJOB; k++)
	{
		arrive[k] = arrive[k-1] + expon(&seed,EXPARRI);
	}
}

void earliest(void)
{
	double min;
	int e;
	earliestqueue = 0;
	min = nextarrive[earliestqueue];	
	isarrive = 1;
	for(e = 0; e < N; e ++)
	{
		if(nextarrive[e] < min)
		{
			min = nextarrive[e];
			isarrive = 1;
			earliestqueue = e;
		}
		if(nextdepart[e] < min)
		{
			min = nextdepart[e];
			isarrive = 0;
			earliestqueue = e;
		}
	}
	earliesttime = min;
}

void arrive_handler(int n, double time, int jobnum)
{
	clock[n] = time;
	printf(" Time%5.1f: Job %d arrives at server %d\r\n", clock[n], jobnum, n);
	j[n] ++;
	if(servstatus[n] == IDLE)
	{
		servstatus[n] = BUSY;
		printf(" Time%5.1f: Job %d starts to get service at server %d\r\n", clock[n], jobnum, n);
		nextdepart[n] = clock[n] + expon(&seed,EXPSERVICE);
	}
	else
	{
		queuelen[n] = queuelen[n] + 1;
		printf(" Time%5.1f: Job %d gets in queue %d which now has %d people\r\n", clock[n], j[n]-1, n, queuelen[n]);
	}
	if((n == 0) && (j[n] < NJOB))
		nextarrive[n] = arrive[j[n]];
	else if ((n != 0) && (j[n] < NJOB))
		nextarrive[n] = nextdepart[n-1] + 0.1;
	else
		nextarrive[n] = INFINITE;
}

void depart_handler(int n, double time, int jobnum)
{
	clock[n] = time;
	printf(" Time%5.1f: Job %d departs from server %d\r\n", clock[n], jobnum, n);
	i[n] ++;
	if (queuelen[n] == 0)
	{
		servstatus[n] = IDLE;
		printf(" Time%5.1f: Server %d status starts to be IDLE\r\n", clock[n], n);
		nextdepart[n] = INFINITE;
	}
	else
	{
		queuelen[n] --;
		servstatus[n] = BUSY;
		printf(" Time%5.1f: Job %d leaves queue %d to start service which now has %d people\r\n", clock[n], i[n], n, queuelen[n]);
		nextdepart[n] = clock[n] + expon(&seed,EXPSERVICE);
	}
	if(n+1 < N)
		nextarrive[n+1] = clock[n] + 0.1;
	else
	{
		printf(" Time%5.1f: Job %d has finished all services\r\n", clock[n], jobnum);
	}
}


int main(void)
{

	//Initialization
	int s;
	for(s = 0; s < N; s++)
	{
		i[s] = 0;
		j[s] = 0;
		clock[s] = 0;
		servstatus[s] = IDLE;
		nextarrive[s] = INFINITE;
		nextdepart[s] = INFINITE;
		queuelen[s] = 0;
	}
	init();
	nextarrive[0] = arrive[0];

	while(finish < NJOB*2*N)
	{
		earliest();
		if(isarrive)
		{
			arrive_handler(earliestqueue, earliesttime, j[earliestqueue]);
		}
		else
		{
			depart_handler(earliestqueue, earliesttime, i[earliestqueue]);
		}
		finish ++;
	}
	getchar();
}
